package com.hexus.eve.actions;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.beimin.eveapi.character.assetlist.AssetListParser;
import com.beimin.eveapi.core.ApiAuthorization;
import com.beimin.eveapi.core.ApiException;
import com.beimin.eveapi.shared.assetlist.ApiAsset;
import com.beimin.eveapi.shared.assetlist.AssetListResponse;
import com.hexus.eve.entities.Account;
import com.hexus.eve.entities.Character;
import com.hexus.eve.entities.Type;
import com.hexus.eve.entities.security.User;
import com.hexus.eve.utils.BlueprintUtils;
import com.hexus.eve.utils.CurrentUser;
import com.hexus.eve.utils.MarketGroupUtils;
import com.hexus.eve.utils.TypeUtils;
import com.opensymphony.xwork2.ActionSupport;


/**
 * Synchronization of all charater's blueprints.<br/>
 * Provides user with list of current user's blueprints (according to the Producteve DB) and list of all blueprints which belong to the user in EVE. 
 * 
 * @author Mikhail_Berastau
 */
public class SynchronizeBlueprints extends ActionSupport {
	private static final long serialVersionUID = 1L;
	private Logger logger = Logger.getLogger(this.getClass());
	
	@Autowired
	SessionFactory sessionFactory;
	@Autowired
	MarketGroupUtils marketGroupUtils;
	
	private Integer characterID;


	public String execute() {
		User user = CurrentUser.getUser();
		List<Account> accounts = user.getAccounts();
		
		//Checking if character which id is passed as parameter really belongs to the user
		Boolean doesCharacterBelongsToUser = false;
		Account account = null;
		Character character = null;
		for(Account a : accounts) {
			for(Character c : a.getCharacters()) {
				if(c.getId().equals(getCharacterID())) {
					account = a;
					character = c;
					doesCharacterBelongsToUser = true;
					break;
				}
				if(doesCharacterBelongsToUser) {
					break;
				}
			}
		}
		
		if(doesCharacterBelongsToUser && account != null && character != null) {
			//Getting all character's assets
			Collection<ApiAsset<ApiAsset<?>>> allAssets = downloadCharacterAssets(account.getUserId(), character.getCharacterID(), account.getApiKey());
			
			//Filtering to leave only blueprints
			List<ApiAsset> blueprintAssets = leaveBlueprintsOnly(allAssets);
			
			System.out.println("Types' IDs(" + blueprintAssets.size() + "):");
			Iterator i = blueprintAssets.iterator();
			while(i.hasNext()){
				//System.out.print(((ApiAsset<ApiAsset<?>>)i.next()).getTypeID() + ((i.hasNext()) ? ", " : ""));
				@SuppressWarnings("unchecked")
				ApiAsset<ApiAsset<?>> a = (ApiAsset<ApiAsset<?>>)i.next();
				Integer id = a.getTypeID();
				TypeUtils typeUtils = TypeUtils.getInstance();
				Type t = TypeUtils.getInstance().getType(id);
				System.out.println("#" + id + " - " + ((t == null) ? "*No item with such id in DB*" : t.getName()) + " x " + a.getQuantity() + " (flag=" + a.getFlag() + ", singleton=" + a.getSingleton() +", rawQuantity=" + a.getRawQuantity() + ")");
			};
			System.out.println();
			/**/
		}
		
		return SUCCESS;
	}
	
	
	/**
	 * Downloads all character's assets.<br/>
	 * Note that some assets can be containers for other assets.
	 * 
	 * @param userID
	 * @param characterID
	 * @param apiKey
	 * @return
	 */
	private Collection<ApiAsset<ApiAsset<?>>> downloadCharacterAssets(Integer userID, Long characterID, String apiKey){
		Collection<ApiAsset<ApiAsset<?>>> results = new ArrayList<ApiAsset<ApiAsset<?>>>();
		ApiAuthorization auth = new ApiAuthorization(userID, characterID, apiKey);
		AssetListParser alp = AssetListParser.getInstance();
		try {
			AssetListResponse alr = alp.getResponse(auth);
			if(!alr.hasError()) {
				results = alr.getAssets();				
			}
		} catch (ApiException e) {
			logger.error("Couldn't get all character's assets from EVE: " + e.getMessage());
		}
		return results;
	}
	
	
	/**
	 * Filters assets, leaves blueprints only.
	 * 
	 * @param allAssets
	 * @param blueprintsMarketGroups
	 * @return
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private List<ApiAsset> leaveBlueprintsOnly(Collection<ApiAsset<ApiAsset<?>>> allAssets) {
		List<ApiAsset> results = new ArrayList<ApiAsset>();
		ApiAsset assets = new ApiAsset<ApiAsset<?>>();
		for(ApiAsset<ApiAsset<?>> a : allAssets) {
			assets.addAsset(a);	
		}
		
		//Starting recursive adding		
		addBlueprints(assets, results, 0);
		return results;
	}

	
	/**
	 * Recursive method to go over all assets <br/>
	 * (assets can contain another assets, so list of items is like a tree).
	 * 
	 * @param asset
	 * @param results
	 * @param blueprintsMarketGroups
	 */
	@SuppressWarnings("rawtypes")
	private void addBlueprints(ApiAsset<?> asset, List<ApiAsset> results, int level) {
		/*
		String border="";
		for(int i = 1; i < level + 1; i++)
			border += "    ";
		
		TypeUtils typeUtils = TypeUtils.getInstance();
		Type t = TypeUtils.getInstance().getType(asset.getTypeID());

		if(asset.getAssets().size() > 0) {
			if(t != null)
				System.out.println(border + t.getName() + " (" + asset.getLocationID() + ")" + " contains: ");
			else 
				System.out.println(border + "*Undefined* (" + asset.getLocationID() + ")" + " contains: ");
		} else
		/**/
		if(BlueprintUtils.getInstance().isBlueprint(asset.getTypeID())){
			//if(t != null) {
				//if(t.getName().startsWith("Station")) {
					//System.out.println(border + t.getName() + " (" + asset.getRawQuantity() + "); location: " + asset.getLocationID());
					results.add(asset);
				//}
			//}
		}
		
		/**/
		
		for(ApiAsset<?> a : asset.getAssets()) {
			addBlueprints(a, results, level + 1);
		}
	}
	
	
	public Integer getCharacterID() {
		return characterID;
	}
	
	public void setCharacterID(Integer characterID) {
		this.characterID = characterID;
	}

}
